/* Copyright (c) 1992-1996  NeXT Software, Inc.  All rights reserved. 
 *
 * QVision.m -- Compaq QVision display driver.
 *
 * HISTORY
 * 30 Sep 92	Joe Pasqua
 *      Created. 
 * 29 June 1993	Derek B Clegg
 *	Cleaned up for external release.
 * 16 Aug 1994 James C. Lee
 *	Add 3.3 bus support & 8-bit color support.
 * 30 Oct 95 Rakesh Dubey
 *	Updated for 4.0.
 */

#import <driverkit/i386/IOEISADeviceDescription.h>
#import "QVision.h"

@implementation QVision

/*
 * Set the brightness to `level'. 
 */
- setBrightness:(int)level token:(int)t
{
    if (level < EV_SCREEN_MIN_BRIGHTNESS || level > EV_SCREEN_MAX_BRIGHTNESS) {
	IOLog("QVision: Invalid arg to setBrightness: %d\n", level);
	return nil;
    }
    brightnessLevel = level;
    [self setGammaTable];
    return self;
}

/*
 * Set the transfer tables. 
 */
- setTransferTable:(const unsigned int *)table count:(int)count
{
    int     k;
    IOBitsPerPixel bpp;
    IOColorSpace cspace;

    if (redTransferTable != 0)
	IOFree(redTransferTable, 3 * transferTableCount);

    transferTableCount = count;

    redTransferTable = IOMalloc(3 * count);
    greenTransferTable = redTransferTable + count;
    blueTransferTable = greenTransferTable + count;

    bpp = [self displayInfo]->bitsPerPixel;
    cspace = [self displayInfo]->colorSpace;

    if (bpp == IO_8BitsPerPixel && cspace == IO_OneIsWhiteColorSpace) {
	for (k = 0; k < count; k++) {
	    redTransferTable[k] = greenTransferTable[k] =
		blueTransferTable[k] = table[k] & 0xFF;
	}
    } else if (cspace == IO_RGBColorSpace &&
	       (bpp == IO_8BitsPerPixel ||
		bpp == IO_12BitsPerPixel ||
		bpp == IO_15BitsPerPixel ||
		bpp == IO_24BitsPerPixel)) {
	for (k = 0; k < count; k++) {
	    redTransferTable[k] = (table[k] >> 24) & 0xFF;
	    greenTransferTable[k] = (table[k] >> 16) & 0xFF;
	    blueTransferTable[k] = (table[k] >> 8) & 0xFF;
	}
    } else {
	IOLog("%s: Can't set transfertable, unknown colorSpace (%d) & pixel depth (%d)\n",[self name], cspace, bpp);
	IOFree(redTransferTable, 3 * count);
	redTransferTable = 0;
    }
    [self setGammaTable];
    return self;
}

/*
 * Put the display into linear framebuffer mode. This typically happens when
 * the window server starts running. 
 */
- (void)enterLinearMode
{
    /* Set up the chip to use the selected mode. */
    [self initializeMode];

    /* Set the gamma-corrected gray-scale palette if necessary. */
    [self setGammaTable];

    /* Enter linear mode. */
    if ([self enableLinearFrameBuffer] == nil) {
	IOLog("%s: Failed to enter linear mode.\n", [self name]);
	return;
    }
}

/*
 * Get the device out of whatever advanced linear mode it was using and back
 * into a state where it can be used as a standard VGA device. 
 */
- (void)revertToVGAMode
{
    /* Reset the VGA parameters. */
    [self resetVGA];

    /* Let the superclass do whatever work it needs to do. */
    [super revertToVGAMode];
}

- initFromDeviceDescription:deviceDescription
{
    IODisplayInfo *displayInfo;
    const IORange *range;
    const QVisionMode *mode;
    IOReturn result;

    if ([super initFromDeviceDescription:deviceDescription] == nil)
	return [super free];

    [self initModeList];	// Initialize the mode list array
    
    if ([self determineConfiguration] == nil) {
	IOLog("Unknown configuration, abort.\n");
	return [super free];
    }

    if ([self selectMode] == nil)
	return [super free];

    redTransferTable = greenTransferTable = blueTransferTable = 0;
    transferTableCount = 0;
    brightnessLevel = EV_SCREEN_MAX_BRIGHTNESS;

    range = [deviceDescription memoryRangeList];
    if (range == 0) {
	IOLog("%s: No memory range specified.\n", [self name]);
	return [super free];
    }
    videoRamAddress = range[0].start;

    displayInfo = [self displayInfo];
    mode = displayInfo->parameters;

    result = [self mapMemoryRange:0 
		to:(vm_address_t *)&(displayInfo->frameBuffer)
		findSpace:YES cache:IO_DISPLAY_CACHE_WRITETHROUGH];
			
    if (result != IO_R_SUCCESS)	{
    	IOLog("%s: IOFrameBufferDisplay: can't map memory (%s)\n",
		[self name], [self stringFromReturn:result]);
	return [super free];
    }
    			
    if (displayInfo->frameBuffer == 0)
        return [super free];
	
    IOLog_dbg(("%s: Initialized `%s'.\n", [self name], mode->name));
    return self;
}

- (unsigned int)displayMemorySize
{
    return installedVRAMBytes;
}

- (unsigned int)ramdacSpeed
{
    return 0;		/* can not determine this */
}

/*
 * Note that we don't use the mapFrameBufferAtPhysicalAddress:length: API
 * anymore. That API is limited and will be obsoleted at a later time. 
 */
- free
{
    [self unmapMemoryRange:0 
    	from:(vm_address_t)[self displayInfo]->frameBuffer];
    return [super free];
}

@end
